package com.lagou.edu.factory;

import com.lagou.edu.annotation.Autowired;
import com.lagou.edu.annotation.Service;
import com.lagou.edu.annotation.Transactional;
import org.reflections.Reflections;
import org.springframework.util.StringUtils;


import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class BeanFactory {

    // 存储对象
    private static Map<String, Object> map = new HashMap<>();

    static {
        //通过包路径获取扫描对象
        Reflections reflections = new Reflections("com.lagou.edu");

        //获取注解为Service的集合
        Set<Class<?>> serviceSet = reflections.getTypesAnnotatedWith(Service.class);

        try {
            for (Class<?> aClass : serviceSet) {
                // 通过反射技术实例化对象
                Object o = aClass.newInstance();
                Service annotation = aClass.getAnnotation(Service.class);
                // 注解有值时则使用value，没有则用类名
                if (StringUtils.isEmpty(annotation.value())) {
                    String[] names = aClass.getName().split("\\.");
                    map.put(names[names.length - 1], o);
                } else {
                    map.put(annotation.value(), o);
                }
            }

            // 检查类的依赖关系
            for (Map.Entry<String, Object> mapEntry : map.entrySet()) {
                Object o = mapEntry.getValue();
                Class c = o.getClass();
                // 获取该类的属性集合
                Field[] fields = c.getDeclaredFields();
                //遍历属性，有Autowired注解时则自动注入
                for (Field field : fields) {
                    if (field.isAnnotationPresent(Autowired.class) && field.getAnnotation(Autowired.class).required()) {
                        String[] names = field.getType().getName().split("\\.");
                        String name = names[names.length - 1];
                        //首字母小写
                        name = StringUtils.uncapitalize(name);
                        Method[] methods = c.getMethods();
                        for (int i = 0; i < methods.length; i++) {
                            Method method = methods[i];
                                if (("set" + name).equalsIgnoreCase(method.getName())) {
                                    method.invoke(o, map.get(name));
                            }
                        }
                    }
                }
                //如果对象类有Transactional注释，则将该对象改为代理对象
                if(c.isAnnotationPresent(Transactional.class)){
                    //获取代理对象工厂
                    ProxyFactory proxyFactory = (ProxyFactory)BeanFactory.getBean("proxyFactory");
                    Class[] tClass = c.getInterfaces();
                    //判断对象是否实现接口
                    if(tClass!=null && tClass.length>0){
                        //实现使用jdk动态代理
                        o = proxyFactory.getJdkProxy(o);
                    }else{
                        //没有则使用CGlib
                        o = proxyFactory.getCglibProxy(o);
                    }
                    //最后把object放入map中
                    map.put(mapEntry.getKey(),o);
                }
            }
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

    }

    public static Object getBean(String id){
        return map.get(id);
    }

}
